`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2020/12/18 21:13:39
// Design Name: 
// Module Name: IIR2nd
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module IIR2nd_tb();

reg clk;
reg rst_n;
wire    [15:0]  filter_out;  
reg    [15:0]  rd_data;
    initial begin
        clk<=0;
        rst_n<=1;
        #50 rst_n <=0;
        #100 rst_n <=1;
    end

        always #5 clk=~clk;
always @(posedge clk) begin
    rd_data<=$random%65535;
end 

    IIR #(16, 4, 5, '{ 
0.999656101597113488921308999124448746443,
0.999656101597113488921308999124448746443, 
0.999101409695275166633621211076388135552,
0.999101409695275166633621211076388135552,
0.998889779817044631826661316154059022665}, // GAIN
'{  '{ 1, -1.999015586917585407533692887227516621351,  1       },              
    '{ 1, -1.999015586917585407533692887227516621351,  1       },              
    '{ 1, -1.999015586917585407533692887227516621351,  1       },
    '{ 1, -1.999015586917585407533692887227516621351,  1       },
    '{ 1, -1.999015586917585407533692887227516621351,  1       }
    },          
'{  '{    -1.998237576320943897911774911335669457912,   0.999290213970775997864848250173963606358},               
    '{    -1.998416449648296788765833298384677618742,   0.999336426916597408975917460338678210974},               
    '{    -1.997140533460913136565295644686557352543,   0.998165874740341796389486717089312151074}, 
    '{    -1.997297197449154460002773703308776021004,   0.998240618265740509151839887636015191674},
    '{    -1.996796239466947175955624516063835471869,   0.997779559634089374675625094823772087693}
    }  )
        u_IIR(clk, !rst_n, 1'b0, rd_data, filter_out);


endmodule


module IIR2nd #(
    parameter DW = 14, FW = 9,
    parameter real GAIN, real NUM[3], real DEN[2]
)(
    input wire clk, rst, en,
    input wire signed [DW-1 : 0] in,    // Q(DW-FW).FW
    output logic signed [DW-1 : 0] out  // Q(DW-FW).FW
);
    function  mul; 
      //����������� 
    input x, y; 
    //���庯���� 
    begin 
        mul=(   ((DW-FW)+(DW-FW)+(FW)+(FW))  '(x)   * ((DW-FW)+(DW-FW)+(FW)+(FW))'(y)  ) >>> ((FW)+(FW)-(FW));
    end 
    endfunction
    wire signed [DW-1:0] n0 = (NUM[0] * 2.0**FW);
    wire signed [DW-1:0] n1 = (NUM[1] * 2.0**FW);
    wire signed [DW-1:0] n2 = (NUM[2] * 2.0**FW);
    wire signed [DW-1:0] d1 = (DEN[0] * 2.0**FW);
    wire signed [DW-1:0] d2 = (DEN[1] * 2.0**FW);
    wire signed [DW-1:0] g  = (GAIN   * 2.0**FW);
    logic signed [DW-1:0] z1, z0;
    wire signed [DW-1:0] pn0 = mul(in, n0);
    wire signed [DW-1:0] pn1 = mul(in, n1);
    wire signed [DW-1:0] pn2 = mul(in, n2);
    wire signed [DW-1:0] o = pn0 + z0;
    wire signed [DW-1:0] pd1 = mul(o, d1);
    wire signed [DW-1:0] pd2 = mul(o, d2);

    always_ff@(posedge clk) begin
        if(rst) begin z0 <= '0; z1 <= '0; out <= '0; end
        else if(en) begin
            z1 <= pn2 - pd2;
            z0 <= pn1 - pd1 + z1;
            out <= mul(o, g);
        end
    end
endmodule

module IIR #(
    parameter DW = 10, EW = 4, STG = 2,
    parameter real GAIN[STG], real NUM[STG][3], real DEN[STG][2]
)(
    input wire clk, rst, en,
    input wire signed [DW-1 : 0] in,
    output logic signed [DW-1 : 0] out
);
    localparam W = EW + DW;
    logic signed [W-1 : 0] sio[STG+1];
    assign sio[0] = in, out = sio[STG];
    generate
        for(genvar s = 0; s < STG; s++) begin
            IIR2nd #(W, DW-1, GAIN[s], NUM[s], DEN[s]) theIir(clk, rst, en, sio[s], sio[s+1]);
        end
    endgenerate
endmodule
